package gdma.hqdes.webapp.controller;

import gdma.hqdes.bean.HqdIndex;
import gdma.hqdes.bean.HqdIndexVer;
import gdma.hqdes.bean.HqdProject;
import gdma.hqdes.bean.Unit;
import gdma.hqdes.service.IndexService;
import gdma.hqdes.service.ProjectService;
import gdma.hqdes.service.UnitService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.vavr.Tuple2;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import sindconsole.auth.bean.Role;
import sindconsole.auth.service.AuthService;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @Author wangyue
 * @Version 3.0
 * @Date 2024-07-25
 */

@RestController
@RequestMapping("/api/search")
public class SearchController {

    @Autowired
    ProjectService projectService;

    @Autowired
    UnitService unitService;

    @Autowired
    IndexService indexService;

    @Autowired
    AuthService authService;

    @Autowired
    StatController statController;

    @ApiOperation("搜索指标版本")
    @GetMapping("/indexes")
    @RequiresAuthentication
    public List<HqdIndexVer> searchIndexVers(@ApiParam("关键字") @RequestParam(value = "keyword", defaultValue = "") String keyword0) {
        String keyword = keyword0.trim();
        try {
            int id = Integer.parseInt(keyword);
            List<HqdIndexVer> result = new ArrayList<>();
            HqdIndexVer hqdIndexVer = indexService.getIndexVersion(id);
            if(hqdIndexVer != null) result.add(hqdIndexVer);
            return result;
        } catch(Exception x) {
            return indexService.listIndexVersions(keyword, Unit.SCOPE_PROVINCIAL);
        }
    }

    @ApiOperation("搜索指标项")
    @GetMapping("/indexes/{verId}")
    @RequiresAuthentication
    public List<HqdIndex> searchIndexItems(@ApiParam("指标版本") @PathVariable("verId") int verId,
                                           @ApiParam("关键字") @RequestParam(value = "keyword", defaultValue = "") String keyword0) {
        String keyword = keyword0.trim();
        try {
            int id = Integer.parseInt(keyword);
            List<HqdIndex> result = new ArrayList<>();
            HqdIndex idx = indexService.getIndex(id);
            if(idx != null) result.add(idx);
            return result;
        } catch(Exception x) {
            List<Integer> verIds = new ArrayList<>();
            verIds.add(verId);
            return indexService.listThinIndexes(verIds, null, keyword);
        }
    }

    @ApiOperation("搜索单位")
    @GetMapping("/units")
    @RequiresAuthentication
    public List<Unit> searchUnits(@ApiParam("关键字") @RequestParam(value = "keyword", defaultValue = "") String keyword0) {
        String keyword = keyword0.trim();
        try {
            int id = Integer.parseInt(keyword);
            List<Unit> result = new ArrayList<>();
            Unit unit = unitService.getUnit(id);
            if(unit != null) result.add(unit);
            return result;
        } catch(Exception x) {
            return unitService.listUnits(null, null, null, keyword, null, Unit.SCOPE_MUNICIPAL, null).getContent();
        }
    }



    @ApiOperation("搜索指定级别单位（同时也会匹配上一级单位，并返回此单位的全部下级单位）")
    @GetMapping("/scopes/{scope}")
    @RequiresAuthentication
    public List<Unit> searchScopedUnits(@ApiParam("单位级别") @PathVariable("scope") int scope,
                                        @ApiParam("关键字") @RequestParam(value = "keyword", defaultValue = "") String keyword0,
                                        @ApiParam("按父级分组：0=不支持，1=支持，2=仅支持") @RequestParam(value = "parentBundle", defaultValue = "1") int parentBundle,
                                        @ApiParam("包括地区") @RequestParam(value = "includesArea", defaultValue = "false") Boolean includesArea) {
        String keyword = keyword0.trim();
        List<Unit> units = unitService.listUnits(null, null, null, keyword, null, Unit.SCOPE_PROVINCIAL, null).getContent();
        if(includesArea) {
            //增加珠三角平均、粤东西北平均两个比较实体
            List<Unit> areas = Unit.AREA_TEXTS.entrySet().stream()
                    .filter(kv -> kv.getValue().contains(keyword))
                    .map(kv -> {
                        Unit unit = new Unit();
                        unit.setScope(scope);
                        unit.setAreaTag(kv.getKey());
                        unit.setName(kv.getValue() + "(平均)");
                        unit.setShortName(unit.getName());
                        return unit;
                    }).collect(Collectors.toList());
            units.addAll(areas);
        }
        if(CollectionUtils.isEmpty(units)) return units;
        units = units.stream()
                .filter(unit -> unit.getScope() == scope || (scope == Unit.SCOPE_COUNTY && parentBundle > 0 && unit.getScope() == Unit.SCOPE_MUNICIPAL))
                .collect(Collectors.toList());
        if(parentBundle > 0) {
            for(Iterator<Unit> it = units.iterator(); it.hasNext(); ) {
                Unit unit = it.next();
                if(unit.getScope() == scope - 1 && unit.getId() != null && CollectionUtils.isEmpty(unit.getChildren())) {
                    List<Unit> children = unitService.getChildUnits(unit.getId());
                    if(CollectionUtils.isEmpty(children)) {
                        it.remove();
                        continue;
                    }
                    unit.setChildren(children);
                }
            }
            List<Tuple2<Unit, Consumer<Unit>>> specialParentUnitList = statController.getSpecialParentUnits(scope);
            if(specialParentUnitList != null) {
                List<Unit> specialParents = specialParentUnitList.stream()
                        .filter(t -> t._1.getName().contains(keyword))
                        .map(t -> {
                            t._2.accept(t._1);
                            return t._1;
                        }).collect(Collectors.toList());
                units.addAll(0, specialParents);
            }
        }
        if(parentBundle == 2)
            units = units.stream().filter(unit -> !CollectionUtils.isEmpty(unit.getChildren())).collect(Collectors.toList());
        return units;
    }

    @ApiOperation("搜索项目")
    @GetMapping("/projects")
    @RequiresAuthentication
    public List<HqdProject> searchProjects(@ApiParam("关键字") @RequestParam(value = "keyword", defaultValue = "") String keyword0) {
        String keyword = keyword0.trim();
        try {
            int id = Integer.parseInt(keyword);
            List<HqdProject> result = new ArrayList<>();
            HqdProject project = projectService.getProject(id);
            if(project != null) result.add(project);
            return result;
        } catch(Exception x) {
            return projectService.listProjects(null, null, null, Unit.SCOPE_MUNICIPAL, keyword);
        }
    }

    @ApiOperation("搜索角色")
    @GetMapping("/roles")
    @RequiresAuthentication
    public List<Role> searchRoles(@ApiParam("指定类型：不填/0=全部，1=功能角色，2=职能角色") @RequestParam(value = "type", defaultValue = "0") int type,
                                  @ApiParam("关键字") @RequestParam(value = "keyword", defaultValue = "") String keyword0) {
        String keyword = keyword0.trim();
        List<Role> roles = authService.findRoles();
        List<Role> funcRoles = roles.stream().filter(role -> Character.isUpperCase(role.getKey().charAt(0))).collect(Collectors.toList());
        List<Role> deptRoles = roles.stream().filter(role -> !role.isPredefined()).collect(Collectors.toList());
        List<Role> result = null;
        if(type == 1) result = funcRoles;
        if(type == 2) result = deptRoles;
        if(result == null) {
            result = funcRoles;
            result.addAll(deptRoles);
        }
        if(StringUtils.hasText(keyword))
            result = result.stream().filter(role -> role.getKey().contains(keyword) | role.getLabel().contains(keyword)).collect(Collectors.toList());
        return result;
    }

}
